﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Algobox.JuicyLib.MarketData;
using Algobox.JuicyLib.SQL.LiquidView;

namespace EODDataSync
{
    class Program
    {
        static EODDataManager _manager;

        const string QUOTEDATE = "--QUOTEDATE=";
        const string QUOTEDATERANGE = "--QUOTEDATERANGE=";
        //const string FXDATE = "-FXDATE=";


        /// <summary>
        /// Connects to the EODData Web Service to download the latest avaliable data for Liquid View
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            // to fix error when run from Telx - very obscure!
            System.Net.ServicePointManager.Expect100Continue = false;

            Console.WriteLine(@"
==========================
Starting EODDataSync
DBCon:          {0}
Binding:        {1}
EODData_USER:   {2}
EODData_Pass:   {3}
LSE_SymbolsMap: {4}
LSE_GBPSymbols: {5}
FX_Symbols:     {6}
==========================",
                           Properties.Settings.Default.LV_DB_CON,
                           Properties.Settings.Default.BINDING,
                           Properties.Settings.Default.USERNAME,
                           Properties.Settings.Default.PASSWORD,
                           Properties.Settings.Default.LSE_SYMBOL_MAP,
                           Properties.Settings.Default.LSE_GBP_SYMBOLS,
                           Properties.Settings.Default.FOREX_SYMBOLS);

            // set up the database helper
            LiquidViewHelper.LiquidViewLinq = new LiquidViewLinqDataContext(Properties.Settings.Default.LV_DB_CON);

            // create the EOD Data soap manager
            _manager = new EODDataManager(Properties.Settings.Default.BINDING);

            // extract symbol mapping for the LSE
            _manager.XLON_SymbolMap = (from csvline in Properties.Settings.Default.LSE_SYMBOL_MAP.Split(',')
                                      let csv = csvline.Split(':')
                                      where csv.Length == 2
                                      select new
                                      {
                                          EOD = csv[0],
                                          UMTF = csv[1]
                                      }).ToDictionary(a => a.EOD, b => b.UMTF);

            // extract all symbols that are in pounds not pence
            Properties.Settings.Default.LSE_GBP_SYMBOLS.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList().ForEach((a) => { _manager.XLON_GBPSymbols.Add(a.Trim()); });

            // extract the currencies we would like to download forex data for
            Properties.Settings.Default.FOREX_SYMBOLS.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList().ForEach((a) => { _manager.FOREX_Symbols.Add(a.Trim()); });


            // log into EOD data web service
            if (!_manager.TryLogin(Properties.Settings.Default.USERNAME, Properties.Settings.Default.PASSWORD))
            {
                Console.WriteLine("Failed to log in to EODData webservice");
            }
            else
            {
                Console.WriteLine("Login successful");

                if (args.Length == 0)                
                {
                    Console.WriteLine("Synchronising...");
                    Synchronise();
                }
                else
                {
                    // check command line arguments
                    foreach (string arg in args)
                    {
                        // get quotes by dates
                        if (arg.Contains(QUOTEDATE))
                        {
                            string dateString = arg.Substring(QUOTEDATE.Length);
                            DateTime date;
                            bool success = DateTime.TryParseExact(
                                dateString,
                                "yyyyMMdd",
                                System.Globalization.CultureInfo.InvariantCulture,
                                System.Globalization.DateTimeStyles.None,
                                out date);

                            if (success)
                            {
                                Console.WriteLine("Quotes by date for {0:yyyyMMdd}", date);
                                QuotesByDate(date);
                            }
                            else
                            {
                                Console.WriteLine("Quotes by date failed to parse date from " + dateString);
                                Help();
                                return;
                            }
                        }
                        else if (arg.Contains(QUOTEDATERANGE))
                        {
                            string dateString = arg.Substring(QUOTEDATERANGE.Length);
                            string dateStringFrom = dateString.Substring(0,8);
                            string dateStringTo = dateString.Substring(9,8);
                            DateTime dateFrom;
                            DateTime dateTo;

                            bool success = DateTime.TryParseExact(
                                dateStringFrom,
                                "yyyyMMdd",
                                System.Globalization.CultureInfo.InvariantCulture,
                                System.Globalization.DateTimeStyles.None,
                                out dateFrom);

                            success &= DateTime.TryParseExact(
                                dateStringTo,
                                "yyyyMMdd",
                                System.Globalization.CultureInfo.InvariantCulture,
                                System.Globalization.DateTimeStyles.None,
                                out dateTo);

                            if (success)
                            {
                                Console.WriteLine("Quotes by date range from {0:yyyyMMdd} to {1:yyyyMMdd}", dateFrom, dateTo);
                                while (dateFrom <= dateTo)
                                {
                                    Console.WriteLine("Fetching quotes from {0:yyyyMMdd}", dateFrom);
                                    QuotesByDate(dateFrom);
                                    dateFrom = dateFrom.AddDays(1);
                                }
                            }
                            else
                            {
                                Console.WriteLine("Quotes by date range failed to parse date from " + dateString);
                                Help();
                                return;
                            }

                        }
                        else
                        {
                            Console.WriteLine("\nUnknown command line switch: " + arg);
                            Help();
                            return;
                        }
                    }
                }
            }

            Console.WriteLine("EODDataSync Finished successfully");
        }


        private static void Synchronise()
        {
            // import latest FX rates
            Console.WriteLine("--== FOREX ==--");
            _manager.TryUpdateForex();


            // create/update the instrument symbols and names
            Console.WriteLine("--== NAMES XNYS ==--");
            if (!_manager.TryUpdateNames(MarketDataConstants.ExchangeMICS.XNYS))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load names for NYSE");

            Console.WriteLine("--== NAMES XNAS ==--");
            if (!_manager.TryUpdateNames(MarketDataConstants.ExchangeMICS.XNAS))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load names for XNAS");

            Console.WriteLine("--== NAMES ARCX ==--");
            if (!_manager.TryUpdateNames(MarketDataConstants.ExchangeMICS.ARCX))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load names for ARCX");

            Console.WriteLine("--== NAMES XTSE ==--");
            if (!_manager.TryUpdateNames(MarketDataConstants.ExchangeMICS.XTSE))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load names for XTSE");

            Console.WriteLine("--== NAMES XTSX ==--");
            if (!_manager.TryUpdateNames(MarketDataConstants.ExchangeMICS.XTSX))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load names for XTSX");


            // insert/update stock splits
            Console.WriteLine("--== SPLITS XNYS ==--");
            if (!_manager.TryUpdateSplits(MarketDataConstants.ExchangeMICS.XNYS))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load splits for NYSE");

            Console.WriteLine("--== SPLITS XNAS ==--");
            if (!_manager.TryUpdateSplits(MarketDataConstants.ExchangeMICS.XNAS))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load splits for XNAS");

            Console.WriteLine("--== SPLITS ARCX ==--");
            if (!_manager.TryUpdateSplits(MarketDataConstants.ExchangeMICS.ARCX))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load splits for ARCX");

            Console.WriteLine("--== SPLITS XTSE ==--");
            if (!_manager.TryUpdateSplits(MarketDataConstants.ExchangeMICS.XTSE))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load splits for XTSE");

            Console.WriteLine("--== SPLITS XTSX ==--");
            if (!_manager.TryUpdateSplits(MarketDataConstants.ExchangeMICS.XTSX))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load splits for XTSX");

            Console.WriteLine("--== SPLITS XLON ==--");
            if (!_manager.TryUpdateSplits(MarketDataConstants.ExchangeMICS.XLON))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load splits for XLON");


            // insert/update eod prices
            Console.WriteLine("--== QUOTES XNYS ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XNYS))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for NYSE");

            Console.WriteLine("--== QUOTES XNAS ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XNAS))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XNAS");

            Console.WriteLine("--== QUOTES ARCX ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.ARCX))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for ARCX");

            Console.WriteLine("--== QUOTES XTSE ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XTSE))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XTSE");

            Console.WriteLine("--== QUOTES XTSX ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XTSX))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XTSX");

            Console.WriteLine("--== QUOTES XLON ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XLON))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XLON");

            Console.WriteLine("--== QUOTES XMIL ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XMIL))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XMIL");

            Console.WriteLine("--== QUOTES XISX ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XISX))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XISX");
        }


        private static void QuotesByDate(DateTime date)
        {
            Console.WriteLine("--== QUOTE DATE XNYS ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XNYS, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for NYSE");

            Console.WriteLine("--== QUOTE DATE XNAS ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XNAS, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XNAS");

            Console.WriteLine("--== QUOTE DATE ARCX ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.ARCX, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for ARCX");

            Console.WriteLine("--== QUOTE DATE XTSE ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XTSE, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XTSE");

            Console.WriteLine("--== QUOTE DATE XTSX ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XTSX, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XTSX");

            Console.WriteLine("--== QUOTE DATE XLON ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XLON, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XLON");

            Console.WriteLine("--== QUOTE DATE XMIL ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XMIL, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XMIL");

            Console.WriteLine("--== QUOTE DATE XISX ==--");
            if (!_manager.TryUpdateQuotes(MarketDataConstants.ExchangeMICS.XISX, date))
                LiquidViewHelper.LogException("EODDataSync", "Failed to load quotes for XISX");
        }

        private static void Help()
        {
            var assembly = System.Reflection.Assembly.GetExecutingAssembly().GetName();
            string process = System.IO.Path.GetFileName(assembly.CodeBase);
            string usage = @"
Usage: {0} [{1}YYYYMMDD] [{2}YYYYMMDD-YYYYMMDD]

    Retrieves fx rates, stock names, stock splits and latest quotes for all exchanges

    Options:
    {1} Retrieves quotes for a specific date for all exchanges
    {2} Retrieves quotes for a range of dates for all exchanges
";
            Console.WriteLine(usage, process, QUOTEDATE, QUOTEDATERANGE);

        }

    }
}
